package com.zqweb.gulimall.order.rabbit;

import com.rabbitmq.client.Channel;
import com.zqweb.gulimall.order.entity.OrderEntity;
import com.zqweb.gulimall.order.entity.OrderReturnReasonEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Arrays;

//@RabbitListener(queues = {"hello-rabbitmq-queue"})
@Service // 要注入到容器中，这样容器在运行时该监听才会动态运行生效
@Slf4j
// 主要用于监听指定队列是否有收到消息，@RabbitListener可标注在类 + 方法上，注意：使用该注解必须标注@EnableRabbit，开启监听支持
public class RabbitTestService {

    @RabbitHandler
    // 只能标注在方法上，主要用于监听时不同处理方法的重载，实现对接收到的不同类型的消息进行封装和处理
    /*
        当客户端（可以有多个）监听到指定队列收到消息后，每个消息都只会被1个客户端接收、消费（接收策略），接收消息时
        可用原生的Message类封装、也可直接用发送消息时的消息类型来封装。而且当前客户端只有接收并处理完成该消息，才会继续
        接收下一个被监听到的消息
     */
    public void receiveMsgOfQueue(Message message, OrderReturnReasonEntity reasonEntity, Channel channel){
        MessageProperties messageHeader = message.getMessageProperties();
        byte[] messageBody = message.getBody();

        System.out.println("接收到的消息头为：" + messageHeader + "\n，消息体为：" + new String(messageBody));
        System.out.println("封装成指定类型，消息为：" + reasonEntity);
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        log.info("消息接收完成！");
    }

    @RabbitHandler
    public void receiveMsgOfQueue(Message message,OrderEntity orderEntity,Channel channel){
        // 获取到接收消息的消息头中的派发标签（每次接收时派发标签会从开始的1进行递增）
        long deliveryTag = message.getMessageProperties().getDeliveryTag();

        System.out.println("封装成指定类型，消息为：" + orderEntity + "\n，deliveryTag = " + deliveryTag);
        try {
            /**
             * 参数1：派发消息的标签
             * 参数2：是否批量的ack
             */
            if (deliveryTag % 2 == 0) {
                // 根据deliveryTag模拟消息处理（为偶数，则签收并手动ack  为奇数，则拒签并根据业务场景是否将消息重新入队）
                channel.basicAck(deliveryTag, false);
                System.out.println("当前消息成功接收并处理，返回ack应答给队列...");
            } else {
                /**
                 * 参数1：派发消息的标签
                 * 参数2：是否批量的nack
                 * 参数3：nack的消息是否重新入队（根据业务场景设置），如果不入队，则直接会将消息丢弃不会再放到队列中
                 */
                channel.basicNack(deliveryTag,false,true);
                System.out.println("当前消息成功接收但不是想要的业务消息数据，返回nack(拒绝应答)，并让消息重新入队，再发一遍...");
            }
        }catch (IOException e) {
            e.printStackTrace();
        }

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

//        log.info("消息接收完成！");
    }


}
